// 
//  ChatClient.cs
//  
//  Author:
//       Christian Winkel <alphawolf1988@gmail.com>
//  
//  Copyright (c) 2012 
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
using System;
using Lypshare.Net.Client;
using Lypshare.Flow;
using Lypshare.Flow.Types;
using Lypshare.Net;
using Lypshare.ChatApp.Packets;
using System.Threading.Tasks;

namespace Lypshare.ChatApp
{
	/// <summary>
	/// Chat client.
	/// </summary>
	/// <exception cref='ArgumentNullException'>
	/// Is thrown when an argument passed to a method is invalid because it is <see langword="null" /> .
	/// </exception>
	public class ChatClient
	{
		// --------------------------------------------------------
        // Class Variables
        // --------------------------------------------------------
		
		
		/// <summary>
		/// The _flow.
		/// </summary>
		private IFlowClient _flow = null;
		
		
		/// <summary>
		/// The _name.
		/// </summary>
		private String _name = null;
		
		
		/// <summary>
		/// The _ready.
		/// </summary>
		private bool _ready = false;
		
		
		// --------------------------------------------------------
        // Class Properties
        // --------------------------------------------------------
		
		
		/// <summary>
		/// Gets a value indicating whether this <see cref="Lypshare.ChatApp.ChatClient"/> is ready.
		/// </summary>
		/// <value>
		/// <c>true</c> if ready; otherwise, <c>false</c>.
		/// </value>
		public bool Ready
		{
			get { return _ready; }
			
		} // Property: Ready
		
		
		// --------------------------------------------------------
        // Class Functions
        // --------------------------------------------------------
		
		
		/// <summary>
		/// Initializes a new instance of the <see cref="Lypshare.ChatApp.ChatClient"/> class.
		/// </summary>
		/// <param name='connection'>
		/// Connection.
		/// </param>
		public ChatClient(IConnection connection)
		{
			if(connection == null)
				throw new ArgumentNullException("connection");
			
			// Initialize flow client with id 1000
			_flow = new FlowClient<GoBackN>(1000);
			
			// Event for closing
			_flow.Closed += OnFlowClosed;
			
			// Event for data received
			_flow.DataReceived += OnFlowDataReceived;
			_flow.Synchronized += OnFlowSynchronized;
			
			Task.Factory.StartNew(()=>
				_flow.Connect(new FlowEndPoint(
					connection, 1000)));
			
		} // Constructor
		
		
		/// <summary>
		/// Send the specified message.
		/// </summary>
		/// <param name='message'>
		/// Message.
		/// </param>
		public void Send(String message)
		{
			// Send message
			_flow.Send(new MessagePacket(message));
			
		} // Send
		
		
		/// <summary>
		/// Releases all resource used by the <see cref="Lypshare.ChatApp.ChatClient"/> object.
		/// </summary>
		/// <remarks>
		/// Call <see cref="Dispose"/> when you are finished using the <see cref="Lypshare.ChatApp.ChatClient"/>. The
		/// <see cref="Dispose"/> method leaves the <see cref="Lypshare.ChatApp.ChatClient"/> in an unusable state. After calling
		/// <see cref="Dispose"/>, you must release all references to the <see cref="Lypshare.ChatApp.ChatClient"/> so the garbage
		/// collector can reclaim the memory that the <see cref="Lypshare.ChatApp.ChatClient"/> was occupying.
		/// </remarks>
		public void Dispose()
		{
			_flow.Close();

		} // Dispose
		
		
		// --------------------------------------------------------
        // Class Handles
        // --------------------------------------------------------
				
		
		/// <summary>
		/// Raises the flow synchronized event.
		/// </summary>
		/// <param name='obj'>
		/// Object.
		/// </param>
		private void OnFlowSynchronized(IFlowClient obj)
		{
			var joinPacket = new JoinPacket(
				MainClass.Name);
			
			// Send join packet
			_flow.Send(joinPacket);
			
			_ready = true;
			
		} // OnFlowSynchronized
		
		
		/// <summary>
		/// Raises the flow data received event.
		/// </summary>
		/// <param name='arg1'>
		/// Arg1.
		/// </param>
		/// <param name='arg2'>
		/// Arg2.
		/// </param>
		private void OnFlowDataReceived(IFlowClient arg1, DataEventArgs arg2)
		{
			if(arg2.Packet is JoinPacket)
			{
				var joinPacket = arg2.Packet 
					as JoinPacket;
				
				_name = joinPacket.Name;
				
				Console.ForegroundColor = ConsoleColor.Red;
				Console.Write("[" + DateTime.Now.ToLongTimeString() + "] ");
				Console.ForegroundColor = ConsoleColor.Gray;
				Console.Write(_name + " ");
				Console.ForegroundColor = ConsoleColor.Blue;
				Console.Write(" joined chat room");
				Console.ForegroundColor = ConsoleColor.White;
				Console.WriteLine();
				Console.WriteLine();
				
			} // if(arg2.Packet is JoinPacket)
			else if(arg2.Packet is MessagePacket)
			{
				var messagePacket = arg2.Packet 
					as MessagePacket;
				
				Console.ForegroundColor = ConsoleColor.Red;
				Console.Write("[" + DateTime.Now.ToLongTimeString() + "] "); 
				Console.ForegroundColor = ConsoleColor.Gray;
	            Console.Write(_name + "> ");
				Console.ForegroundColor = ConsoleColor.Green;
				Console.Write(messagePacket.Message);
				Console.ForegroundColor = ConsoleColor.White;
				Console.WriteLine();
				Console.WriteLine();
				
			} // else if(arg2.Packet is MessagePacket)
		} // OnFlowDataReceived
		
		
		/// <summary>
		/// Raises the flow closed event.
		/// </summary>
		/// <param name='obj'>
		/// Object.
		/// </param>
		private void OnFlowClosed(IFlowClient obj)
		{
			if(_name != null)
			{
				Console.ForegroundColor = ConsoleColor.Red;
				Console.Write("[" + DateTime.Now.ToLongTimeString() + "] ");
				Console.ForegroundColor = ConsoleColor.Gray;
				Console.Write(_name + " ");
				Console.ForegroundColor = ConsoleColor.Blue;
				Console.Write(" left chat room");
				Console.ForegroundColor = ConsoleColor.White;
				Console.WriteLine();
				Console.WriteLine();
				
			} // if(_name != null)
		} // OnFlowClosed
		
	} // public class ChatClient
} // namespace Lypshare.ChatApp